Scroll the desktop model picker as one region - #2310
Merged
SawyerHood merged 1 commit intoAug 23, 2026
Conversation
## What was wrong
The desktop model menu held two scroll regions. The popover capped itself
at the Radix available height and scrolled, while the model list kept its
own `shrink-0 max-h-[min(250px, available - 80px)]` scroller inside it. The
80px constant does not cover the real chrome: the provider tabs, the search
field, the reasoning rows, the fast-mode toggle and the footer action add up
to ~295px. So in a short viewport the model list held its full height, the
reasoning rows sat below the fold, and the wheel or touch gesture that
started over the models was captured by the inner scroller. A user reported
that the reasoning options at the bottom were unreachable after zooming in.
## What changed
`apps/app/src/components/pickers/ModelReasoningPicker.tsx` gives the desktop
menu a single scroll region. The popover is now `overflow-hidden` and pins
the provider tabs and the search field. A new body element under
`MenuHoverProvider` owns `min-h-0 flex-1 overflow-y-auto overscroll-contain`,
so the model rows, the reasoning rows, the fast-mode toggle and the footer
action scroll together. The model list drops its desktop cap and scroller,
which also moves its sticky section labels onto the shared region. The
compact drawer path keeps its previous markup.
## How you verified
- Reproduced in the dev app through doobie at 1000x520 and 1000x400: the
reasoning section ended 161px below the viewport, and a wheel gesture over
the models only moved the inner list.
- After the change, one wheel gesture reveals every reasoning option and the
fast-mode toggle at both heights, and clicking "Ultra" at 1000x400 commits
the level. A 1000x900 viewport still shows the whole menu with no scroller.
The 500x800 compact drawer is unchanged.
- Replaced the picker's desktop scroll test with one that asserts a single
scroll region containing both the models listbox and the reasoning rows.
It fails on the previous code ("expected [ ...(2) ] to have a length of 1")
and passes now.
- `pnpm exec turbo run typecheck lint test build --filter=@bb/app`
(3288 tests passed).
> AGENT GENERATED
SawyerHood
deleted the
bb/fix-doobie-modal-selector-repro-thr_bih52wg67b
branch
August 23, 2026 15:51
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What was wrong
The desktop model menu held two scroll regions. The popover capped itself at the Radix available height and scrolled, while the model list kept its own
shrink-0 max-h-[min(250px, available - 80px)]scroller inside it (added in #1596). The 80px constant does not cover the real chrome: the provider tabs (33px), the search field (37px), the reasoning rows (189px), the fast-mode toggle (34px) and the dividers add up to ~295px. So in a short viewport the model list held its full height, the reasoning rows sat below the fold, and the wheel or touch gesture that started over the models was captured by the inner scroller instead of the popover. A user reported that the reasoning options at the bottom were unreachable after zooming in.Measured on
mainat a 1000x520 viewport: the popover was 341px tall with 536px of content, and the reasoning section ended at y=681 — 161px below the viewport.What changed
apps/app/src/components/pickers/ModelReasoningPicker.tsxgives the desktop menu a single scroll region.overflow-hiddenand pins the provider tabs and the search field (shrink-0).MenuHoverProviderownsmin-h-0 flex-1 overflow-y-auto overscroll-contain, so the model rows, the reasoning rows, the fast-mode toggle and the footer action scroll together.Trade-off: on a tall viewport with a very long list (for example during a search), the reasoning rows are no longer pinned below a 250px model scroller. One predictable scroll region is worth more than a pin that only held while the menu fit anyway.
No wire or CLI surface changed.
How you verified
Browser checks through the doobie CLI against the dev app, Codex provider (8 models, 6 reasoning levels):
5.6-Sol Ultra)Also confirmed the search field stays pinned during a search and that arrow-key navigation still scrolls the highlighted row into view at 1000x400.
Tests: replaced the picker's desktop scroll test with
scrolls the desktop models and reasoning rows as one region, which asserts exactly one scroll region and that it contains both the models listbox and the reasoning rows. It fails on the previous code (expected [ …(2) ] to have a length of 1 but got 2) and passes now.Commands:
pnpm exec turbo run typecheck --filter=@bb/apppnpm exec turbo run lint --filter=@bb/apppnpm exec turbo run test --filter=@bb/app(422 files, 3288 tests passed)pnpm exec turbo run build --filter=@bb/appReported by a user over DM; no GitHub issue was open for it.